package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepository;
import com.atguigu.tingshu.search.repository.SuggestIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Resource
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Resource
    private CategoryFeignClient categoryFeignClient;
    @Resource
    private UserInfoFeignClient userInfoFeignClient;
    @Resource  // 继承 ElasticsearchRepository 接口即可
    private AlbumIndexRepository albumIndexRepository;
    @Resource
    private SuggestIndexRepository suggestIndexRepository;
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;
    @Resource
    private ElasticsearchClient elasticsearchClient;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private RedissonClient redissonClient;

    @Override
    public void upperAlbum(Long albumId) {
        //  一共需要远程获取哪些数据，将获取到的数据赋值给AlbumInfoIndex
        // 新建一个空的AlbumInfoIndex对象对其进行赋值即可
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        // 属性赋值

        // 异步编排
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            // 远程调用专辑服务获取专辑数据
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            // 判断albumInfoResult 是否为空
            Assert.notNull(albumInfoResult, "远程调用专辑服务获取专辑数据失败");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "远程调用专辑服务获取专辑数据albumInfo失败");
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);

            // 属性数据  通过专辑ID获得属性ID以及属性值信息
            List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
            // 循环遍历数据进行赋值
            List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueVoList.stream().map(albumAttributeValue -> {
                // 创建新对象
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                // 属性赋值
                attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                // 数据返回
                return attributeValueIndex;
            }).toList();
            albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
            //数据返回
            return albumInfo;
        }, threadPoolExecutor).exceptionally(ex -> {
            log.error(ex.getMessage());
            return new AlbumInfo();
        });

        CompletableFuture<Void> categoryCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            // 分类数据 通过专辑ID获得分类ID以及分类信息 一级分类ID和二级分类ID和三级分类ID
            Result<BaseCategoryView> categoryViewResult = categoryFeignClient.getCategoryView(albumInfo.getCategory3Id());
            Assert.notNull(categoryViewResult, "远程调用专辑服务获取专辑分类数据失败");
            BaseCategoryView baseCategoryView = categoryViewResult.getData();
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
        }, threadPoolExecutor).exceptionally(ex -> {
            log.error(ex.getMessage());
            return null;
        });

        CompletableFuture<Void> userCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            // 远程调用用户服务获取用户数据
            // 使用用户ID查看用户昵称  需要考虑上架时是创建专辑的用户上传还是管理员上传
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(albumInfo.getUserId());
            Assert.notNull(userInfoVoResult, "远程调用用户服务获取用户数据失败");
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            // 判断
            Assert.notNull(userInfoVo, "远程调用用户服务获取用户数据userInfoVo失败");
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
        }, threadPoolExecutor).exceptionally(ex -> {
            log.error(ex.getMessage());
            return null;
        });


        CompletableFuture<AlbumListVo> albumListVoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            // 统计数据 播放量、评论数、点赞数、收藏数
            Result<AlbumListVo> albumStatistics = albumInfoFeignClient.getAlbumStatistics(albumId);
            Assert.notNull(albumStatistics, "远程调用专辑服务获取专辑统计数据失败");
            AlbumListVo albumListVo = albumStatistics.getData();
            Assert.notNull(albumListVo, "远程调用专辑服务获取专辑统计数据albumListVo失败");
            return albumListVo;
        }, threadPoolExecutor).exceptionally(ex -> {
            log.error(ex.getMessage());
            return new AlbumListVo();
        });
        CompletableFuture<Void> albumStartsCompletableFuture = albumListVoCompletableFuture.thenAcceptAsync(albumListVo -> {
            albumInfoIndex.setPlayStatNum(albumListVo.getPlayStatNum());
            albumInfoIndex.setSubscribeStatNum(albumListVo.getSubscribeStatNum());
            albumInfoIndex.setBuyStatNum(albumListVo.getBuyStatNum());
            albumInfoIndex.setCommentStatNum(albumListVo.getCommentStatNum());
            albumInfoIndex.setHotScore(new Random().nextDouble(100000));
        }, threadPoolExecutor).exceptionally(ex -> {
            log.error(ex.getMessage());
            return null;
        });

        // get 方法只调用一次
        try {
            if (ObjectUtils.isEmpty(albumInfoCompletableFuture.get()) || ObjectUtils.isEmpty(albumListVoCompletableFuture.get())) {
                log.error("远程调用失败");
                return;
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        // 多任务组合
        CompletableFuture.allOf(
                albumInfoCompletableFuture,
                categoryCompletableFuture,
                userCompletableFuture,
                albumListVoCompletableFuture,
                albumStartsCompletableFuture
        ).join();
        // 将上架的专辑数据(albumInfoIndex)保存到es中
        albumIndexRepository.save(albumInfoIndex);

        // 保存提词库
        SuggestIndex suggestIndex = new SuggestIndex();
        // 赋值 专辑标题
        suggestIndex.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndex.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        suggestIndexRepository.save(suggestIndex);
        // 赋值 专辑简介
        SuggestIndex suggestIndexIntro = new SuggestIndex();
        suggestIndexIntro.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndexIntro.setTitle(albumInfoIndex.getAlbumIntro());
        suggestIndexIntro.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        suggestIndexIntro.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumIntro())}));
        suggestIndexIntro.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumIntro())}));
        suggestIndexRepository.save(suggestIndexIntro);

        // 赋值 专辑作者
        SuggestIndex suggestIndexAnnouncer = new SuggestIndex();
        suggestIndexAnnouncer.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndexAnnouncer.setTitle(albumInfoIndex.getAnnouncerName());
        suggestIndexAnnouncer.setKeyword(new Completion(new String[]{albumInfoIndex.getAnnouncerName()}));
        suggestIndexAnnouncer.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAnnouncerName())}));
        suggestIndexAnnouncer.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAnnouncerName())}));
        suggestIndexRepository.save(suggestIndexAnnouncer);

        //	将新增的商品SKUID存入布隆过滤器
//	获取布隆过滤器，将新增skuID存入布隆过滤器
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);

    }

    @Override
    public void lowerAlbum(Long albumId) {
        albumIndexRepository.deleteById(albumId);
    }


    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //动态获取参数 构建查询条件 dsl语句
        SearchRequest searchRequest = this.queryBuildDsl(albumIndexQuery);
        //  生成dsl语句  执行dsl语句   返回结果
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //进行数据类型转换   转换成我们想要的东西
        AlbumSearchResponseVo searchResponseVo = this.parseResultData(searchResponse);
        searchResponseVo.setTotal(searchResponse.hits().total().value());
        searchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        searchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        //  设置总页数
        searchResponseVo.setTotalPages(searchResponseVo.getTotal() % albumIndexQuery.getPageSize() == 0 ?
                searchResponseVo.getTotal() / albumIndexQuery.getPageSize() :
                searchResponseVo.getTotal() / albumIndexQuery.getPageSize() + 1);
        // 返回对象
        return searchResponseVo;
    }

    /**
     * 数据转换 解析结果
     *
     * @param searchResponse
     * @return
     */
    public AlbumSearchResponseVo parseResultData(SearchResponse<AlbumInfoIndex> searchResponse) {
        // 返回对象
        // 创建对象
        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();
        // 存储专辑列表集合 List<AlbumInfoIndexVo>  hits.hist.source
        List<AlbumInfoIndexVo> AlbumInfoIndexVoList = searchResponse.hits().hits().stream().map(hit -> {
            // 获取到专辑数据 创建对象
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            // 赋值
            AlbumInfoIndex albumInfoIndex = hit.source();
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
            // 数据 返回
            //  高亮数据判断
            if (null != hit.highlight().get("albumTitle")) {
                //  获取高亮标题
                String albumTitle = hit.highlight().get("albumTitle").get(0);
                albumInfoIndexVo.setAlbumTitle(albumTitle);
            }
            return albumInfoIndexVo;
        }).toList();
        albumSearchResponseVo.setList(AlbumInfoIndexVoList);
        return albumSearchResponseVo;
    }

    /**
     * 构建查询条件  dsl 语句
     *
     * @param albumIndexQuery
     * @return
     */
    public SearchRequest queryBuildDsl(AlbumIndexQuery albumIndexQuery) {
        // 通过Builder() 方法 创建一个对象
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();
        searchRequestBuilder.index("albuminfo");
        // query ---> bool ---> should ---> match
        BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();
        // 检索的入口  根据关键词
        /**
         * "query": {
         *     "bool": {
         *       "should": [
         *         {
         *           "match": {
         *             "albumTitle": "三国"
         *           }
         *         },
         *         {
         *           "match": {
         *             "albumIntro": "三国"
         *           }
         *         },
         *         {
         *           "match": {
         *             "announcerName": "三国"
         *           }
         *         }
         *       ]
         *     }
         *   }
         */
        if (!StringUtils.isEmpty(albumIndexQuery.getKeyword())) {
            boolQueryBuilder.should(s -> s.match(m -> m.field("albumTitle").query(albumIndexQuery.getKeyword())));
            boolQueryBuilder.should(s -> s.match(m -> m.field("albumIntro").query(albumIndexQuery.getKeyword())));
            boolQueryBuilder.should(s -> s.match(m -> m.field("announcerName").query(albumIndexQuery.getKeyword())));
            //设置高亮  与query平级
            /**
             "highlight": {
             "fields": {"albumTitle": {}},
             "pre_tags": ["<span style=color:red>"],
             "post_tags": ["</span>"]
             }
             **/

            searchRequestBuilder.highlight(h -> h.fields("albumTitle", f -> f.preTags("<span style=color:red>").postTags("</span>")));
        }
        // 检索分类 一级分类 二级分类 三级分类
        /**
         * "query": {
         *     "bool": {
         *       "filter": [
         *         {
         *           "term": {
         *             "category1Id": "2"
         *           }
         *         },
         *         {
         *           "term": {
         *             "category2Id": "104"
         *           }
         *         },
         *         {
         *           "term": {
         *             "category3Id": "1019"
         *           }
         *         }
         *       ]
         *     }
         *   }
         */
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory1Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category1Id").value(albumIndexQuery.getCategory1Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory2Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category2Id").value(albumIndexQuery.getCategory2Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory3Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category3Id").value(albumIndexQuery.getCategory3Id())));
        }
        // 根据属性与属性值过滤  与should同级
        /**
         * "filter": [
         *         {
         *           "nested": {
         *             "path": "attributeValueIndexList",
         *             "query": {
         *               "bool": {
         *                 "must": [
         *                   {
         *                     "match": {
         *                       "attributeValueIndexList.attributeId": "1"
         *                     }
         *                   },
         *                   {
         *                     "match": {
         *                       "attributeValueIndexList.valueId": "2"
         *                     }
         *                   }
         *                 ]
         *               }
         *             }
         *           }
         *         }
         *       ],
         */
        List<String> attributeList = albumIndexQuery.getAttributeList();
        //判断集合是否为空
        if (!CollectionUtils.isEmpty(attributeList)) {
            // 循环遍历
            for (String attribute : attributeList) {
                // 将attract进行分割
                String[] split = attribute.split(":");
                // 判断数组是否为空
                if (!ObjectUtils.isEmpty(split)) {
                    if (split.length == 2) {
                        boolQueryBuilder.filter(f -> f.nested(n -> n.path("attributeValueIndexList")
                                .query(q -> q.bool(b -> b.must(m -> m.match(m1 -> m1.field("attributeValueIndexList.attributeId").query(split[0])))
                                        .must(m -> m.match(m1 -> m1.field("attributeValueIndexList.valueId").query(split[1])))
                                ))
                        ));
                    }
                }
            }
        }
        // 排序 与query平级  动态入值
        /**
         * "sort": [
         *     {
         *       "hotScore": {
         *         "order": "desc"
         *       }
         *     }
         *   ]
         */
        String order = albumIndexQuery.getOrder();
        if (!StringUtils.isEmpty(order)) {
            // 分割
            String[] sort = order.split(":");
            if (sort.length == 2 && null != sort) {
                String field = "";
                // 判断
                switch (sort[0]) {
                    case "1":
                        field = "hotScore";
                        break;
                    case "2":
                        field = "playStatNum";
                        break;
                    case "3":
                        field = "createTime";
                        break;
                }
                // 设置排序字段与排序规则
                String finalField = field;
                searchRequestBuilder.sort(s -> s.field(f -> f.field(finalField).order("asc".equals(sort[1]) ? SortOrder.Asc : SortOrder.Desc)));
            }
        }
        //  分页 与 query同级
        /**
         * "from": 0,
         *   "size": 20
         */
        int from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        searchRequestBuilder.from(from);
        BoolQuery boolQuery = boolQueryBuilder.build();
        // 两种均可
//        Query.Builder builder = new Query.Builder();
//        Query query = builder.build();
        // 构建查询条件 query{}
        searchRequestBuilder.query(boolQuery._toQuery());
        SearchRequest searchRequest = searchRequestBuilder.build();
        System.out.println("dsl===========================================:\t" + searchRequest.toString());
        // 返回对象
        return searchRequest;
    }

    @Override
    public List<Map<String, Object>> channel(Long category1Id) {
        // 获取到一级分类下的所有三级分类数据
        Result<List<BaseCategory3>> baseCategory3ResultList = categoryFeignClient.findTopBaseCategory3(category1Id);
        // 判断
        Assert.notNull(baseCategory3ResultList, "获取数据失败");
        List<BaseCategory3> baseCategory3List = baseCategory3ResultList.getData();
        // 将baseCategory3List 转换为 map 集合  key = category3Id  value = baseCategory3
        Map<Long, BaseCategory3> category3Map = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));
        Assert.notNull(baseCategory3List, "远程调用三级分类数据失败");
        List<Long> category3IdList = baseCategory3List.stream().map(BaseCategory3::getId).toList();
        /**
         * dsl 语句  先用三级分类ID进行过滤 然后分组，然后取前6条 然后按照热度进行降序排列
         * GET /albuminfo/_search
         * {
         *   "query": {
         *     "bool": {
         *       "filter": [
         *         {
         *           "terms": {
         *             "category3Id": [
         *               "1001",
         *               "1002",
         *               "1003",
         *               "1004",
         *               "1005",
         *               "1006",
         *               "1007"
         *             ]
         *           }
         *         }
         *       ]
         *     }
         *   },
         *   "aggs": {
         *     "aggs_category3Id": {
         *       "terms": {
         *         "field": "category3Id",
         *         "size": 10
         *       },
         *       "aggs": {
         *         "agg_topSix": {
         *           "top_hits": {
         *             "size": 6,
         *             "sort": [
         *               {
         *                 "hotScore": {
         *                   "order": "desc"
         *                 }
         *               }
         *             ]
         *           }
         *         }
         *       }
         *     }
         *   }
         * }
         */
        //  执行dsl语句 获取结果
        // value<List<FieldValue>> category3IdList的泛型是Long
        // 此时需要将category3IdList集合中的数据转换为List<FieldValue>类型
        List<FieldValue> fieldValueList = category3IdList.stream().map(category3Id -> FieldValue.of(category3Id)).toList();
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                            .query(q -> q.bool(b -> b.filter(f -> f.terms(t -> t.field("category3Id").terms(t1 -> t1.value(fieldValueList))))))
                            .aggregations("aggs_category3Id", a -> a.terms(t -> t.field("category3Id"))
                                    .aggregations("agg_topSix", a1 -> a1.topHits(t -> t.size(6)
                                            .sort(s1 -> s1.field(f -> f.field("hotScore").order(SortOrder.Desc)))))
                            )
                    , AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 从结果集中获得专辑数据
        Aggregate aggregate = searchResponse.aggregations().get("aggs_category3Id");
        List<Map<String, Object>> listMap = aggregate.lterms().buckets().array().stream().map(bucket -> {
            Map<String, Object> map = new HashMap<>();
            // 获取三级分类ID
            long category3Id = bucket.key();
            // 获取专辑集合数据
            Aggregate aggTopSix = bucket.aggregations().get("agg_topSix");
            List<AlbumInfoIndex> albumInfoIndexList = aggTopSix.topHits().hits().hits().stream().map(hit -> {
                String data = hit.source().toString();
                AlbumInfoIndex albumInfoIndex = JSONObject.parseObject(data, AlbumInfoIndex.class);
                return albumInfoIndex;
            }).toList();
            // 用三级ID获取三级对象
            map.put("baseCategory3", category3Map.get(category3Id));
            map.put("list", albumInfoIndexList);
            return map;
        }).toList();
        return listMap;
    }

    @Override
    public List<String> completeSuggest(String keyword) {
        // 1.根据用户输入的数据。从es中获得数据然后返回给用户  keyword-suggest  keywordPinyin-suggest  keywordSequence-suggest
        //   数据载体实体类 在专辑上架时对其进行赋值
        // 执行dsl语句查询并返回结果集
        /**
         * GET /suggestinfo/_search
         *                                                        {
         * 							  "suggest": {
         * 								"keyword-suggest": {
         * 								  "prefix": "sanguo",
         * 								  "completion": {
         * 									"field": "keyword",
         * 									"skip_duplicates": true,
         * 									"fuzzy": {
         * 									  "fuzziness": 2
         *                                    }
         *                                  }
         *                                },
         * 								"keywordPinyin-suggest": {
         * 								  "prefix": "sanguo",
         * 								  "completion": {
         * 									"field": "keywordPinyin",
         * 									"skip_duplicates": true,
         * 									"fuzzy": {
         * 									  "fuzziness": 2
         *                                    }
         *                                  }
         *                                },
         * 								"keywordSequence-suggest": {
         * 								  "prefix": "sanguo",
         * 								  "completion": {
         * 									"field": "keywordSequence",
         * 									"skip_duplicates": true,
         * 									"fuzzy": {
         * 									  "fuzziness": 2
         *                                    }
         *                                  }
         *                                }
         *                              }
         *                            }
         */
        SearchResponse<SuggestIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("suggestinfo")
                            .suggest(s1 -> s1
                                    .suggesters("keyword-suggest", s2 -> s2
                                            .prefix(keyword)
                                            .completion(c -> c
                                                    .field("keyword")
                                                    .skipDuplicates(true)
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .size(10)))
                                    .suggesters("keywordPinyin-suggest", s2 -> s2
                                            .prefix(keyword)
                                            .completion(c -> c
                                                    .field("keywordPinyin")
                                                    .skipDuplicates(true)
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .size(10)))
                                    .suggesters("keywordSequence-suggest", s2 -> s2
                                            .prefix(keyword)
                                            .completion(c -> c
                                                    .field("keywordSequence")
                                                    .skipDuplicates(true)
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .size(10)))
                            )
                    , SuggestIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //获取集合数据 数据都在options里面

        List<String> list1 = getSuggestionTitle(searchResponse, "keyword-suggest");
        List<String> list2 = getSuggestionTitle(searchResponse, "keywordPinyin-suggest");
        List<String> list3 = getSuggestionTitle(searchResponse, "keywordSequence-suggest");
        List<String> list = new ArrayList<String>();
        list.addAll(list1);
        list.addAll(list2);
        list.addAll(list3);
//        searchResponse.suggest().get("keyword-suggest");
//        searchResponse.suggest().get("keywordPinyin-suggest");
//        searchResponse.suggest().get("keywordSequence-suggest");
        // 数据返回
        return list;
    }

    public List<String> getSuggestionTitle(SearchResponse<SuggestIndex> searchResponse, String suggest) {
        // 获取题词库里面的数据
        List<Suggestion<SuggestIndex>> suggestionList = searchResponse.suggest().get(suggest);
        if (!CollectionUtils.isEmpty(suggestionList)) {
            for (Suggestion<SuggestIndex> suggestIndexSuggestion : suggestionList) {
                // 获取数据
                List<String> list = suggestIndexSuggestion.completion().options().stream().map(option -> {
                    String title = option.source().getTitle();
                    return title;
                }).toList();
                // 返回集合数据
                return list;
            }
            ;
        }
        // 默认返回空集合
        return new ArrayList<>();
    }


    @Override
    public void updateLatelyAlbumRanking() {
//        1. 先查询所有一级分类数据
        Result<List<BaseCategory1>> baseCatrgory1Result = categoryFeignClient.findAllCategory1();
        Assert.notNull(baseCatrgory1Result, "查询一级分类数据失败");
        List<BaseCategory1> baseCategory1List = baseCatrgory1Result.getData();
        Assert.notNull(baseCategory1List, "查询一级分类数据baseCategory1List失败");
        // 循环遍历一级分类数据
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            // 声明一个数组存储五个需要排序的维度
            String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
            for (String rankingDimension : rankingDimensionArray) {
//        2. 按照每个维度来统计排行 热度:hotScore、播放量:playStatNum、订阅量:subscribeStatNum、购买量:buyStatNum、评论数:commentStatNum
                // 执行dsl语句查询数据
                /**
                 * GET /albuminfo/_search
                 * {
                 *   "query": {
                 *     "term": {
                 *       "category1Id": {
                 *         "value": "1"
                 *       }
                 *     }
                 *   },
                 *   "sort": [
                 *     {
                 *       "subscribeStatNum": {
                 *         "order": "desc"
                 *       }
                 *     }
                 *   ]
                 * }
                 */
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                                    .query(q -> q.term(t -> t.field("category1Id").value(baseCategory1.getId())))
                                    .sort(s1 -> s1.field(f -> f.field(rankingDimension).order(SortOrder.Desc)))
                            , AlbumInfoIndex.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                //获取排好序的数据
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
//        3. 从es中重新获取排序之后的专辑信息，并写入缓存中
                // 将数据存储到redis缓存
                redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX + baseCategory1.getId(), rankingDimension, albumInfoIndexList);
            }
        }
    }

//    public void updateLatelyAlbumRanking() {
//        //  获取到所有的一级分类数据;
//        Result<List<BaseCategory1>> baseCategory1Result = categoryFeignClient.findAllCategory1();
//        //  判断;
//        Assert.notNull(baseCategory1Result, "远程调用获取一级分类失败");
//        List<BaseCategory1> baseCategory1List = baseCategory1Result.getData();
//        Assert.notNull(baseCategory1List, "远程调用获取一级分类失败");
//        //  循环遍历;
//        for (BaseCategory1 baseCategory1 : baseCategory1List) {
//            //  声明一个数组或集合来存储五个排序的维度;
//            String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
//            for (String rankingDimension : rankingDimensionArray) {
//                //  执行dsl语句查询数据
//                SearchResponse<AlbumInfoIndex> searchResponse = null;
//                try {
//                    searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
//                                    .query(q -> q.term(t -> t.field("category1Id").value(baseCategory1.getId())))
//                                    .sort(st -> st.field(f -> f.field(rankingDimension).order(SortOrder.Desc)))
//                            ,
//                            AlbumInfoIndex.class);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//                //  获取到排序之后的数据;
//                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
//                //  将数据存储到缓存;
//                redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX + baseCategory1.getId(), rankingDimension, albumInfoIndexList);
//            }
//        }
//    }

    //    @Override
//    public List<AlbumInfoIndex> findRankingList(Long category1Id, String ranking) {
//        List<AlbumInfoIndex> list = (List<AlbumInfoIndex>) redisTemplate.opsForHash().get(RedisConstant.RANKING_KEY_PREFIX + category1Id, ranking);
//        return list;
//    }
    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String ranking) {
        //  获取排行榜
        List<AlbumInfoIndex> list = (List<AlbumInfoIndex>) redisTemplate.opsForHash().get(RedisConstant.RANKING_KEY_PREFIX + category1Id, ranking);
        return list;
    }

}
